#include <gtest/gtest.h>

#include <cstring>
#include <stdexcept>
#include <utility>

#include "storage/disk_scheduler.h"

class CreateDBFileHelper {
 public:
  explicit CreateDBFileHelper(const std::string& db_file) {
    db_io_.open(db_file, std::ios::binary | std::ios::trunc | std::ios::out |
                             std::ios::in);
    if (!db_io_.is_open()) {
      std::invalid_argument("can't open db file");
    }
  }
  void CreateDBFile(uint32_t nums) {
    // 创建一个缓冲区
    char* buffer = new char[boltDB::BOLTDB_PAGE_SIZE];
    memset(buffer + sizeof(uint32_t), 0,
           boltDB::BOLTDB_PAGE_SIZE - sizeof(uint32_t));
    // 在缓冲区的开始位置放置一个uint32_t类型的值
    for (uint32_t i = 0; i < nums; i++) {
      memcpy(buffer, &i, sizeof(uint32_t));
      // 剩余缓冲区填充为0或其他数据
      db_io_.write(buffer, boltDB::BOLTDB_PAGE_SIZE);
    }
  }

 private:
  std::fstream db_io_;
};

TEST(TestDiskManager, basic_io) {
  char* buffer = new char[boltDB::BOLTDB_PAGE_SIZE];
  memset(buffer, 0, boltDB::BOLTDB_PAGE_SIZE);
  auto disk_manager = boltDB::DiskManager("test.db");
  boltDB::page_id_t page_id = 0;
  for (; page_id < 5; page_id++) {
    memcpy(buffer, &page_id, sizeof(uint32_t));
    // 剩余缓冲区填充为0或其他数据
    disk_manager.WritePage(page_id, buffer);
  }
  disk_manager.ReadPage(1, buffer);
  uint32_t pageId;
  memcpy(&pageId, buffer, sizeof(uint32_t));
  EXPECT_EQ(pageId, 1);

  disk_manager.ReadPage(0, buffer);
  memcpy(&pageId, buffer, sizeof(uint32_t));
  EXPECT_EQ(pageId, 0);

  disk_manager.ReadPage(2, buffer);
  memcpy(&pageId, buffer, sizeof(uint32_t));
  EXPECT_EQ(pageId, 2);
}

TEST(TestDiskScheduler, basic_schedule) {
  auto disk_manager = boltDB::DiskManager("test_sheduler.db");
  auto disk_scheduler = boltDB::DiskScheduler(&disk_manager);
  char* buffer = new char[boltDB::BOLTDB_PAGE_SIZE];
  memset(buffer, 0, boltDB::BOLTDB_PAGE_SIZE);

  boltDB::page_id_t page_id = 0;
  for (; page_id < 5; page_id++) {
    memcpy(buffer, &page_id, sizeof(uint32_t));
    // 剩余缓冲区填充为0或其他数据
    auto write_promise = disk_scheduler.CreatePromise();
    auto write_future = write_promise.get_future();
    auto write_request = boltDB::DiskRequest{true, buffer, page_id, std::move(write_promise)};
    disk_scheduler.Schedule(std::move(write_request));
    EXPECT_EQ(write_future.get(), true);
  }
  memset(buffer, 0, boltDB::BOLTDB_PAGE_SIZE);
  auto read_promise = disk_scheduler.CreatePromise();
  auto read_future = read_promise.get_future();
  auto read_request = boltDB::DiskRequest{false, buffer, 4, std::move(read_promise)};
  disk_scheduler.Schedule(std::move(read_request));
  EXPECT_EQ(read_future.get(), true);

  uint32_t pageId;
  memcpy(&pageId, buffer, sizeof(uint32_t));
  EXPECT_EQ(pageId, 4);
}